package org.munoz.client;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsonUtils;
import com.google.gwt.dom.client.AudioElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.media.client.Audio;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import org.munoz.client.Presenter.View;
import org.munoz.client.gwtfb.sdk.FBCore;
import org.munoz.shared.Card;
import org.munoz.shared.Deck;
import org.munoz.shared.GameResult;
import org.munoz.shared.Player;
import org.munoz.shared.Rank;
import org.munoz.shared.State;
import org.munoz.shared.Suit;

public class Graphics extends Composite implements View {
	private static GameImages gameImages = GWT.create(GameImages.class);
    private static GraphicsUiBinder uiBinder = GWT.create(GraphicsUiBinder.class);
    private static GameSounds gameSounds = GWT.create(GameSounds.class);
    
    interface GraphicsUiBinder extends UiBinder<Widget, Graphics> {}
    @UiField GameCss css;
    @UiField Label gameStatus;
    @UiField Label playerTurn;
    @UiField (provided=true) FlexTable cardsInHandTable;
    @UiField (provided=true) FlexTable groupsPlayer1Table;
    @UiField (provided=true) FlexTable groupsPlayer2Table;
    @UiField Label requestCard;
    @UiField Label cardsInDeck;
    @UiField HorizontalPanel HorPan;
    @UiField VerticalPanel divider;
    //@UiField Button resetButton; // Random game HW#5
    @UiField Button play;
    @UiField TextBox adversary;
    @UiField ListBox liveMatches;
    @UiField Button delete;
    @UiField Button logout;
    @UiField Button automatch;
    @UiField Label userNameAndEmailUI;
    @UiField Label opponentNameUI;
    @UiField Label matchIdUI;
    
    @UiField Label or;
    
    // HW#8
    @UiField Label startMatchDate;
    @UiField Label cardsInDeckMessage;
    @UiField Label player1;
    @UiField Label player2;
    @UiField Label tableCardsDivisor;
    @UiField Label rankingUI;
    
    @UiField Button aiButton;
        
    private Image[] cardsInHand;
    private Audio shuffleDeck;
    private Audio introSound;
	private String opName = "";
	private int myOrder;
    private static GoFishMessages msgInt = GWT.create(GoFishMessages.class);

    @UiField Button friendsButton; 

    /**
     * Creates the view of the game. 
     */
    public Graphics() {
    	cardsInHandTable = new FlexTable();
		groupsPlayer1Table = new FlexTable();
		groupsPlayer2Table = new FlexTable(); 
		divider = new VerticalPanel();
		divider.setWidth("100");
		requestCard = new Label();
		HorPan = new HorizontalPanel();
        initWidget(uiBinder.createAndBindUi(this));
        
        if (Audio.isSupported()) {
            shuffleDeck = Audio.createIfSupported();
            shuffleDeck.addSource(gameSounds.cardsShuffleMp3().getSafeUri()
            		.asString(), AudioElement.TYPE_MP3);
            shuffleDeck.addSource(gameSounds.cardsShuffleWav().getSafeUri()
            		.asString(), AudioElement.TYPE_WAV);
            
            introSound = Audio.createIfSupported();
            introSound.addSource(gameSounds.introMp3().getSafeUri()
            		.asString(), AudioElement.TYPE_MP3);
            introSound.addSource(gameSounds.introWav().getSafeUri()
            		.asString(), AudioElement.TYPE_WAV);
        }
        disableBoard();
    }

    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#setStartDate(java.lang.String)
     */
    public void setStartDate(String sDate){
    	Date date = new Date(Long.valueOf(sDate));
    	startMatchDate.setText(msgInt.start() + " " + DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_SHORT).format(date) + " "
                + DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.TIME_SHORT).format(date));
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#setRankingUI(java.lang.String)
     */
    public void setRankingUI(String ranking){
    	rankingUI.setText(ranking);
    }
    
   /* (non-Javadoc)
    * @see org.munoz.client.Presenter.View#disableBoard()
    */
    @Override 
   public void disableBoard(){
	   delete.setEnabled(false);
	   automatch.setEnabled(false);
	   play.setEnabled(false);
	   adversary.setEnabled(false);
	   liveMatches.setEnabled(false);
	   logout.setEnabled(false);
//	   resetButton.setEnabled(false);
	   delete.setVisible(false);
	   automatch.setVisible(false);
	   play.setVisible(false);
	   adversary.setVisible(false);
	   liveMatches.setVisible(false);
	   logout.setVisible(false);
	   or.setText("");
	   aiButton.setEnabled(false);
	   aiButton.setVisible(false);
	   friendsButton.setEnabled(false);
	   friendsButton.setVisible(false);
   }
      
   
   /* (non-Javadoc)
    * @see org.munoz.client.Presenter.View#enableBoard()
    */
    @Override 
   public void enableBoard(){
//	   delete.setEnabled(true);
//	   delete.setText(msgInt.deleteButton());
//	   automatch.setEnabled(true);
//	   automatch.setText(msgInt.automatchButton());
//	   play.setEnabled(true);
//	   play.setText(msgInt.playButton());
//	   adversary.setEnabled(true);
//	   adversary.setText(msgInt.adversaryEmailInput());
//	   liveMatches.setEnabled(true);
//	   logout.setEnabled(true);
////	   resetButton.setEnabled(false);
//	   delete.setVisible(true);
//	   automatch.setVisible(true);
//	   play.setVisible(true);
//	   adversary.setVisible(true);
//	   liveMatches.setVisible(true);
//	   logout.setVisible(true);
//	   logout.setText(msgInt.logoutButton());
//	   or.setText(msgInt.or());
	   aiButton.setText(msgInt.aiButton());
	   aiButton.setVisible(true);
	   aiButton.setEnabled(true);
	   friendsButton.setText(msgInt.friendsButton());
	   friendsButton.setEnabled(true);
	   friendsButton.setVisible(true);
   }
   
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getMessageCardsInDeck()
     */
    public Label getMessageCardsInDeck(){
    	return cardsInDeckMessage;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#setWhoseTurn(int, int)
     */
    @Override
    public void setWhoseTurn(int stateTurn, int player){
        if(player == -1){
    		playerTurn.setText(msgInt.waitingOpponent());
    		gameStatus.setText("");
        }
//        else if(player == State.PLAYER1 || player == State.PLAYER2){
//    		playerTurn.setText("Turn?? Todo");        	
//        }
//    	if(player == State.PLAYER1){
        else if(player == stateTurn){
//    		playerTurn.setText("Player 1's turn");
    		playerTurn.setText(msgInt.yourMove());
    		myOrder = player;
    	}
        // Game over
        else if(player == 100 && stateTurn == 80){
        	playerTurn.setText(msgInt.gameOver());
        }
    	else {
    		playerTurn.setText(msgInt.waitingOpMove());
    	}    	
    }
    
    public Button getFriendsButton(){
    	return friendsButton;
    }
    
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getAIButton()
     */
    public Button getAIButton(){
    	return aiButton;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#enableOnlyAI()
     */
    public void enableOnlyAI(){
 	   aiButton.setText(msgInt.aiButton());
 	   aiButton.setVisible(true);
 	   aiButton.setEnabled(true);
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getResetButton()
     */
    @Override
    public HasClickHandlers getResetButton() {
        // return resetButton; // HW#5
    	return null;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getAutomatchButton()
     */
    @Override
    public Button getAutomatchButton(){
    	return automatch;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getPlayButton()
     */
    @Override
    public HasClickHandlers getPlayButton(){
    	return play;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getLogoutButton()
     */
    @Override 
    public HasClickHandlers getLogoutButton(){
    	return logout;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getDeleteButton()
     */
    @Override
    public HasClickHandlers getDeleteButton(){
    	return delete;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getEmailOpponentTextBox()
     */
    @Override
    public TextBox getEmailOpponentTextBox(){
    	return adversary;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getListOfMatches()
     */
    @Override
    public ListBox getListOfMatches(){
    	return liveMatches;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getSelectedMatch()
     */
    @Override
    public Long getSelectedMatch() {
        if (liveMatches.getSelectedIndex() == 0)
            return null;
        return Long.valueOf(liveMatches.getValue(liveMatches.getSelectedIndex()));
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#getCardRequested()
     */
    @Override
    public Label getCardRequested(){
    	return requestCard;
    }
    
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#playShuffleDeckSound()
     */
    @Override
    public void playShuffleDeckSound() {
    	if (shuffleDeck != null){
    		shuffleDeck.play();
    	}
    }

    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#playIntroSound()
     */
    @Override
    public void playIntroSound(){
    	if(introSound != null){
    		introSound.play();
    	}
    }
    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#isLocalStorageSupported()
     */
    @Override
    public boolean isLocalStorageSupported() {
    	return Storage.isLocalStorageSupported();
    }

    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#readValueFromLocalStorage(java.lang.String)
     */
    @Override
    public String readValueFromLocalStorage(String key) {
    	Storage local = Storage.getLocalStorageIfSupported();
    	return local == null ? null : Storage.getLocalStorageIfSupported()
                            .getItem(key);
    }

    /* (non-Javadoc)
     * @see org.munoz.client.Presenter.View#writeValueToLocalStorage(java.lang.String, java.lang.String)
     */
    @Override
    public void writeValueToLocalStorage(String key, String value) {
    	Storage local = Storage.getLocalStorageIfSupported();
        if (local != null) {
                if (value != null)
                        local.setItem(key, value);
                else
                        local.removeItem(key);
        }
    }
    
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setCardsInHand(org.munoz.shared.Deck)
	 */
	@Override
	public void setCardsInHand(Deck hand) {
		cardsInHandTable.removeAllRows();
//		final Image image = new Image();
		cardsInHand = new Image[hand.getNumberOfCardsRemaining()];
		int suitPos = 0;
		int rankPos = 0; 
		int n = 0;
		ArrayList<Card> inHand = hand.getOrderedCards();
		for(Card c : inHand){//hand.getCards()){			
			Image image = new Image();
			image.setResource(imageHelper(c));
//			suitPos = c.getSuit().ordinal() *123;
//			rankPos = c.getRank().ordinal() * 79;
			//image.setVisibleRect(rankPos, suitPos, 79, 123);
			image.setTitle(c.suitToString() + " " + c.rankToString());
			cardsInHandTable.setWidget(0, n, image);
//			cardsInHandTable.setText(1, n, c.suitToString() + " " + c.rankToString());
			cardsInHand[n] = image;
			n++;        

		} 
	}
	

	
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#getCardsInHandImages()
	 */
	@Override
	public Image[] getCardsInHandImages() {
		return cardsInHand;
	}
	
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#getGameImages()
	 */
	@Override
	public GameImages getGameImages(){
		return gameImages;
	}
	
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setUserNameAndEmailUI(java.lang.String)
	 */
	@Override
	public void setUserNameAndEmailUI(String nameAndEmail){
		userNameAndEmailUI.setText(nameAndEmail);
	}
	
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setOpponentNameUI(java.lang.String)
	 */
	@Override
	public void setOpponentNameUI(String opponentName){
		opponentNameUI.setText(opponentName);
	}

	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setMatchIdUI(java.lang.String)
	 */
	@Override
	public void setMatchIdUI(String matchId){
		matchIdUI.setText(matchId);
	}

	

	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setStateOfGame(org.munoz.shared.GameResult, int, boolean)
	 */
	@Override
	public void setStateOfGame(GameResult gameResult, int cardsInD, boolean gameInitialized, boolean loggedIn) {
		if(gameResult == null && gameInitialized){
			gameStatus.setText(msgInt.playAgainst() + " " /*"GAME IN PROGRESS AGAINST"*/ + opName);
			cardsInDeck.setText("" + cardsInD);
			if(myOrder == State.PLAYER1){
				player1.setText(msgInt.myGroups() + "---");
				player2.setText("---" + msgInt.opponentGroups());
			}
			else{
				player1.setText(msgInt.opponentGroups() + "---");
				player2.setText("---" + msgInt.myGroups());
			}
			tableCardsDivisor.setText(msgInt.tableCardsMsg());
		}
		else if(gameResult == null && !gameInitialized && loggedIn){
			gameStatus.setText(msgInt.chooseOptions());
			cardsInDeck.setText("");
			playerTurn.setText("");
			cardsInDeckMessage.setText("");
			
		}
		else if(gameResult == null && !gameInitialized && !loggedIn){
			gameStatus.setText(msgInt.pleaseLogin());
			cardsInDeck.setText("");
		}
		else{
			int winner = gameResult.getWinner();
			String winStr;
			if(winner == myOrder){
				gameStatus.setText(msgInt.youWon());
			}
			else if(winner == State.TIE){
				gameStatus.setText(msgInt.tie());
			}
			else {
				gameStatus.setText(msgInt.youLost());
			}
			playerTurn.setText("");
		}
		
	}

	//TODO: Fix this. I can do it more efficient because I don't need to add all the content of the tables everytime.
	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#setGroupOfCardsInTable(org.munoz.shared.State)
	 */
	@Override
	public void setGroupOfCardsInTable(State state) {
		Player pl1 = state.getPlayers()[State.PLAYER1];
		Player pl2 = state.getPlayers()[State.PLAYER2];
		int suitPos = 0;
		int rankPos = 0;
		int n = 0;
		int m = 0;
		groupsPlayer1Table.removeAllRows();
		groupsPlayer2Table.removeAllRows();
		// Player 1
		if(pl1.getNumberOfRankGroups() > 0){
			for(Rank r : pl1.getPlayerFourRankCardsPlacedInTable()){
				Image image = new Image();
				image.setResource(gameImages.cards());
				//suitPos = i*123;
				//rankPos = i * 79;
				image.setVisibleRect(r.ordinal()*79, suitPos, 79, 123);
				groupsPlayer1Table.setWidget(m, n, image);
				n++;
				if(n>3){
					n = 0; 
					m++;
				}
			}		
		}
		// Player 2
		suitPos = 0;
		rankPos = 0;
		n=0;
		m=0;
		if(pl2.getNumberOfRankGroups() > 0){
			for(Rank r : pl2.getPlayerFourRankCardsPlacedInTable()){
				Image image = new Image();
				image.setResource(gameImages.cards());
				//suitPos = i*123;
				//rankPos = i * 79;
				image.setVisibleRect(r.ordinal()*79, suitPos, 79, 123);
				groupsPlayer2Table.setWidget(m, n, image);
				n++;
				if(n>3){
					n = 0; 
					m++;
				}
			}		
		}
	}

	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#clearView(org.munoz.shared.State)
	 */
	@Override
	public void clearView(State state) {
	    this.setGroupOfCardsInTable(state);
	}


	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#displayOpName(java.lang.String)
	 */
	@Override
	public void displayOpName(String opponentName) {
		opName = opponentName;
		
	}

	/* (non-Javadoc)
	 * @see org.munoz.client.Presenter.View#imageHelper(org.munoz.shared.Card)
	 */
	@Override
	public ImageResource imageHelper(Card c) {
		if(c.getSuit() == Suit.CLUBS){
			switch(c.getRank()){
				case ACE:
					return gameImages.CLUBS_ACE();
				case TWO:
					return gameImages.CLUBS_TWO();
				case THREE:
					return gameImages.CLUBS_THREE();
				case FOUR:
					return gameImages.CLUBS_FOUR();
				case FIVE:
					return gameImages.CLUBS_FIVE();
				case SIX:
					return gameImages.CLUBS_SIX();
				case SEVEN:
					return gameImages.CLUBS_SEVEN();
				case EIGHT:
					return gameImages.CLUBS_EIGHT();
				case NINE:
					return gameImages.CLUBS_NINE();
				case TEN:
					return gameImages.CLUBS_TEN();
				case JACK:
					return gameImages.CLUBS_JACK();
				case QUEEN:
					return gameImages.CLUBS_QUEEN();
				case KING:
					return gameImages.CLUBS_KING();
				default:
					return gameImages.backOfCard();
			}
		}
		if(c.getSuit() == Suit.DIAMONDS){
			switch(c.getRank()){
			case ACE:
				return gameImages.DIAMONDS_ACE();
			case TWO:
				return gameImages.DIAMONDS_TWO();
			case THREE:
				return gameImages.DIAMONDS_THREE();
			case FOUR:
				return gameImages.DIAMONDS_FOUR();
			case FIVE:
				return gameImages.DIAMONDS_FIVE();
			case SIX:
				return gameImages.DIAMONDS_SIX();
			case SEVEN:
				return gameImages.DIAMONDS_SEVEN();
			case EIGHT:
				return gameImages.DIAMONDS_EIGHT();
			case NINE:
				return gameImages.DIAMONDS_NINE();
			case TEN:
				return gameImages.DIAMONDS_TEN();
			case JACK:
				return gameImages.DIAMONDS_JACK();
			case QUEEN:
				return gameImages.DIAMONDS_QUEEN();
			case KING:
				return gameImages.DIAMONDS_KING();
			default:
				return gameImages.backOfCard();
			}
		}
		if(c.getSuit() == Suit.HEARTS){
			switch(c.getRank()){
			case ACE:
				return gameImages.HEARTS_ACE();
			case TWO:
				return gameImages.HEARTS_TWO();
			case THREE:
				return gameImages.HEARTS_THREE();
			case FOUR:
				return gameImages.HEARTS_FOUR();
			case FIVE:
				return gameImages.HEARTS_FIVE();
			case SIX:
				return gameImages.HEARTS_SIX();
			case SEVEN:
				return gameImages.HEARTS_SEVEN();
			case EIGHT:
				return gameImages.HEARTS_EIGHT();
			case NINE:
				return gameImages.HEARTS_NINE();
			case TEN:
				return gameImages.HEARTS_TEN();
			case JACK:
				return gameImages.HEARTS_JACK();
			case QUEEN:
				return gameImages.HEARTS_QUEEN();
			case KING:
				return gameImages.HEARTS_KING();
			default:
				return gameImages.backOfCard();
			}
		}
		if(c.getSuit() == Suit.SPADES){
			switch(c.getRank()){
			case ACE:
				return gameImages.SPADES_ACE();
			case TWO:
				return gameImages.SPADES_TWO();
			case THREE:
				return gameImages.SPADES_THREE();
			case FOUR:
				return gameImages.SPADES_FOUR();
			case FIVE:
				return gameImages.SPADES_FIVE();
			case SIX:
				return gameImages.SPADES_SIX();
			case SEVEN:
				return gameImages.SPADES_SEVEN();
			case EIGHT:
				return gameImages.SPADES_EIGHT();
			case NINE:
				return gameImages.SPADES_NINE();
			case TEN:
				return gameImages.SPADES_TEN();
			case JACK:
				return gameImages.SPADES_JACK();
			case QUEEN:
				return gameImages.SPADES_QUEEN();
			case KING:
				return gameImages.SPADES_KING();
			default:
				return gameImages.backOfCard();
			}
		}
		return gameImages.backOfCard(); // TODO: Change this for back of card.
	}

}